﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Negocio
{
    public class Artigo
    {
        #region Metodos

        /// <summary>
        /// Recupera uma lista de entidades de negocio "Artigo".
        /// </summary>
        public List<Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Entidades.Artigo> ConsultarArtigo()
        {
            Dados.Artigo dados = new Dados.Artigo();
            return dados.ConsultarArtigo();
        }

        /// <summary>
        /// Recupera uma entidade de negocio "Artigo".
        /// </summary>
        public Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Entidades.Artigo ObterArtigo(int id)
        {
            Dados.Artigo dados = new Dados.Artigo();
            return dados.ObterArtigo(id);
        }

        /// <summary>
        /// Persiste uma entidade de negocio "Artigo".
        /// </summary>
        public void InserirArtigo(Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Entidades.Artigo artigo)
        {
            Dados.Artigo dados = new Dados.Artigo();

            Entidades.PalavraChave palavraChave = new Entidades.PalavraChave();
            palavraChave.CodigoArtigo = dados.InserirArtigo(artigo);
            palavraChave.NomePalavraChave = artigo.Solucao;

            InserirPalavraChave(palavraChave);
        }

        /// <summary>
        /// Remove uma entidade de negocio "Artigo".
        /// </summary>
        public void ExcluirArtigo(int id)
        {
            Dados.Artigo dados = new Dados.Artigo();
            dados.ExcluirArtigo(id);
        }

        /// <summary>
        /// Atualiza uma entidade de negocio "Artigo".
        /// </summary>
        public void AtualizarArtigo(Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Entidades.Artigo artigo)
        {
            Dados.Artigo dados = new Dados.Artigo();
            dados.AtualizarArtigo(artigo);
        }

        /// <summary>
        /// Persiste palavras chaves e as relaciona com os artigos.
        /// </summary>
        public void InserirPalavraChave(Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Entidades.PalavraChave palavraChave)
        {
            string[] textoQuebrado = palavraChave.NomePalavraChave.Split(' ');
            foreach (string textoPedaco in textoQuebrado)
            {
                string textoSoundex = string.Format("{0}", Soundex(textoPedaco));
 
                if (textoSoundex != string.Empty && textoSoundex.Length > 1)
                {
                    palavraChave.NomePalavraChave = textoSoundex;
                    Dados.Artigo dados = new Dados.Artigo();
                    dados.InserirPalavraChave(palavraChave);
                }
            }
        }

        /// <summary>
        /// Método responsável para geração da soudex da palavra
        /// </summary>
        /// <param name="palavra"></param>
        /// <returns></returns>
        private string Soundex(string palavra)
        {
            string palavra_sub = palavra.ToLower();
            string nova_palavra = string.Empty;
            const string letrasAcentuadas = "áàâãéèêíìîóòôõúùûüç";
            const string letrasSemAcento = "aaaaeeeiiioooouuuuc";
            foreach (char letra in palavra_sub.ToCharArray())
            {
                char novaLetra;
                if (letrasAcentuadas.IndexOf(letra) >= 0)
                    novaLetra = letrasSemAcento.Substring(letrasAcentuadas.IndexOf(letra), 1).ToCharArray()[0];
                else
                    novaLetra = letra;

                if (novaLetra == 'b' || novaLetra == 'f' || novaLetra == 'p' || novaLetra == 'v')
                {
                    nova_palavra += "b";
                    continue;
                }

                if (novaLetra == 'c' || novaLetra == 'g' || novaLetra == 'j' || novaLetra == 'k' || novaLetra == 'q')
                {
                    nova_palavra += "c";
                    continue;
                }

                if (novaLetra == 's' || novaLetra == 'x' || novaLetra == 'z')
                {
                    nova_palavra += "s";
                    continue;
                }

                if (novaLetra == 'm' || novaLetra == 'n')
                {
                    nova_palavra += "m";
                    continue;
                }

                if (novaLetra == 'r')
                {
                    nova_palavra += "r";
                    continue;
                }

                if (novaLetra == 'l')
                {
                    nova_palavra += "l";
                    continue;
                }

                if (novaLetra == 'd' || novaLetra == 't')
                {
                    nova_palavra += "d";
                    continue;
                }



                if (letra == '1' || letra == '2' || letra == '3' || letra == '4' || letra == '5' || letra == '6' || letra == '7' || letra == '8' || letra == '9' || letra == '0')
                {
                    nova_palavra += letra;
                    continue;
                }

            }

            return nova_palavra;
        }

        /// <summary>
        /// Retorna resultado da pesquisa de Artigos
        /// </summary>
        public Entidades.ResultadoBuscaArtigo RetornarListaArtigos(string termo, int pagina, int qtdPagina)
        {
           Entidades.ResultadoBuscaArtigo retorno = new Bovespa.Sinacor.Servico.BaseConhecimento.Artigo.Entidades.ResultadoBuscaArtigo();
            
           List<Entidades.Artigo> artigos = RetornarArtigos(termo);

           if(artigos.Count > 0)
           {
                const int paginas = 20;
                int numeroPaginas = artigos.Count / qtdPagina;
                int itemInicial = (pagina * qtdPagina) - (qtdPagina - 1);
                StringBuilder tabelaPaginacao = new StringBuilder();

                retorno.Artigos = artigos.GetRange(itemInicial - 1, Math.Min(artigos.Count, qtdPagina));

                tabelaPaginacao.Append("<table><tr>");
                if (numeroPaginas <= paginas)
                {
                    for (int item = 1; item <= pagina; item++)
                        tabelaPaginacao.AppendFormat(
                            (item == pagina) ?
                                "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'><b>{0}</b></a></td>" :
                                "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'>{0}</a></td>",
                             item.ToString(), termo);
                }
                else if (numeroPaginas > paginas)
                {
                    if (pagina <= (paginas / 2))
                    {
                        for (int item = 1; item <= (paginas / 2); item++)
                            tabelaPaginacao.AppendFormat(
                                (item == pagina) ?
                                    "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'><b>{0}</b></a></td>" :
                                    "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'>{0}</a></td>",
                                 item.ToString(), termo);
                        if (pagina < (numeroPaginas - 10))
                            tabelaPaginacao.AppendFormat(
                                "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'>Próximo</a></td>",
                                ((paginas / 2) + 1),
                                termo);
                    }
                    else
                    {
                        tabelaPaginacao.AppendFormat(
                            "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'>Anterior</a></td>",
                            (pagina - 10),
                            termo);
                        for (int item = (pagina - 9); item <= (pagina + 10) && item <= numeroPaginas; item++)
                            tabelaPaginacao.AppendFormat(
                                (item == pagina) ?
                                    "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'><b>{0}</b></a></td>" :
                                    "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'>{0}</a></td>",
                                item.ToString(), termo);
                        if (pagina < (numeroPaginas - 10))
                            tabelaPaginacao.AppendFormat(
                                "<td><a href='ResultadoPesquisa.aspx?termo={1}&pagina={0}'>Próximo</a></td>",
                                (pagina + 11),
                                termo);
                    }

                }
                tabelaPaginacao.Append("</tr></table>");
                retorno.TextoPaginacao = string.Format("{0}", tabelaPaginacao.ToString());
           }

           return retorno;
        }

        private List<Entidades.Artigo> RetornarArtigos(string termo)
        {
            List<Entidades.Artigo> retorno = new List<Entidades.Artigo>();
            StringBuilder clausula = new StringBuilder();
            List<string> listaPalavrasDestaque = new List<string>();
            if (termo.IndexOf(' ') > 0)
            {
                string[] palavras = termo.Split(' ');
                foreach (string palavra in palavras)
                {
                    if (palavra != string.Empty && palavra.Length > 1)
                    {
                        listaPalavrasDestaque.Add(palavra);
                        string texto = Soundex(palavra);
                        clausula.AppendFormat("{0} nm_palavra_chave = '{1}'", clausula.Length <= 0 ? String.Empty : " or ", texto);
                    }
                }
            }
            else
            {
                listaPalavrasDestaque.Add(termo);
                string texto = Soundex(termo);
                clausula.AppendFormat(" nm_palavra_chave = '{0}'", texto);
            }
            List<long> listaCodigoPalavras = new Dados.Artigo().RetornarIdsPalavrasChaves(clausula.ToString());
            if (listaCodigoPalavras.Count > 0)
            {
                #region quando há palavras-chaves
                StringBuilder listaPalavras = new StringBuilder();
                foreach (int codigo in listaCodigoPalavras)
                {
                    listaPalavras.Append(listaPalavras.Length > 0 ? " or " : String.Empty);
                    listaPalavras.AppendFormat(" apc.cd_palavra_chave = {0} ", codigo);
                }
                List<Entidades.Artigo> artigos = new Dados.Artigo().RetornarArtigosPalavrasChaves(listaPalavras.ToString());
                if (artigos.Count > 0)
                {
                    foreach(Entidades.Artigo artigo in artigos) {
                        artigo.Solucao = GerarTrecho(artigo.Solucao, listaPalavrasDestaque);
                        retorno.Add(artigo);
                    }
                }
                #endregion
            }
            return retorno;
        }

        public string GerarTrecho(string texto, IList<string> listaPalavras)
        {
            List<posicaoPalavras> listaPosicao = new List<posicaoPalavras>();

            foreach (string palavra in listaPalavras)
            {
                int posInicial = texto.ToUpper().IndexOf(palavra.ToUpper());
                if (posInicial < 0) continue;
               
                if (texto.Substring(0, posInicial).Contains("."))
                    posInicial = texto.LastIndexOf('.', posInicial, texto.Length - posInicial);
                
                int posFinal = posInicial + 200;
                
                if (posFinal > (texto.Length - 1))
                    posFinal = texto.Length - 1;
                
                posicaoPalavras obj = new posicaoPalavras();
                obj.Inicial = posInicial;
                obj.Final = posFinal;
                listaPosicao.Add(obj);
            }

            StringBuilder sb = new StringBuilder();
            if (listaPosicao.Count > 0)
            {
                sb.Append("..." + texto.Substring(listaPosicao[0].Inicial, listaPosicao[0].Final - listaPosicao[0].Inicial) + "...");

                foreach (string palavra in listaPalavras)
                    sb.Replace(palavra, string.Format("<b>{0}</b>", palavra));
            }
            return sb.ToString();
        }

        /*
        public List<Entidades.Artigo> RetornarArtigosOrdenados(List<RetornoPalavras> lista)
        {
            List<int> artigos = new List<int>();

            List<Entidades.Artigo> artigo = new List<Entidades.Artigo>();

            int id_artigo = 0;
            foreach (RetornoPalavras retorno in lista)
            {
                if (id_artigo != retorno.ID)
                    artigos.Add(retorno.ID);

                id_artigo = retorno.ID;
            }


            foreach (int id in artigos)
            {
                List<RetornoPalavras> retorno = lista.FindAll(delegate(RetornoPalavras match)
                {
                    if (match.ID == id)
                        return true;
                    return false;
                });

                //int relevancia = 0;
                List<Keywords> key = new List<Keywords>();

                foreach (RetornoPalavras ret in retorno)
                {

                    foreach (RetornoPalavras retinterno in retorno)
                    {
                        if (retinterno.Keyword != ret.Keyword)
                        {
                            int diferenca = retinterno.Posicao - ret.Posicao;
                            if (diferenca < 0)
                                diferenca = diferenca * -1;


                            Keywords keyword = key.Find(delegate(Keywords match)
                            {
                                if ((match.Keyword1 == ret.Keyword
                                    && match.Keyword2 == retinterno.Keyword)
                                    || match.Keyword1 == retinterno.Keyword
                                    && match.Keyword2 == ret.Keyword)
                                    return true;
                                return false;
                            });

                            if (keyword == null)
                            {
                                Keywords keyWords = new Keywords();
                                keyWords.Keyword1 = ret.Keyword;
                                keyWords.Keyword2 = retinterno.Keyword;
                                keyWords.Posicao = diferenca;
                                keyWords.ID = id;
                                key.Add(keyWords);
                            }
                            else
                                if (diferenca <= keyword.Posicao)
                                    keyword.Posicao = diferenca;

                        }
                    }
                }

                //verifica a lista de keywords
                int relevancia = 0;
                foreach (Keywords word in key)
                {
                    relevancia += word.Posicao;
                }

                Entidades.Artigo objArtigo = new Entidades.Artigo();
                objArtigo.ID = id;
                objArtigo.Relevancia = relevancia;
                objArtigo.ListaPalavras = retorno;
                artigo.Add(objArtigo);
            }
            return artigo;
        }
        */

        #endregion

        private class posicaoPalavras
        {
            private int _inicial;
            private int _final;

            public int Inicial
            {
                get { return _inicial; }
                set { _inicial = value; }
            }

            public int Final
            {
                get { return _final; }
                set { _final = value; }
            }

        }
    }
}
